//============================================================================
// Name        : H1.cpp
// Author      : Lucifer
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C, Ansi-style
//============================================================================
#include "pch.h"
#include <unistd.h>

#define LOG_TAG "MAIN"

void test1_fun1(void *arg) {
    const char *str = arg;
    for (int i = 0; i < 10; i++) {
        printf("%s (%d) \n", str, i);
        fflush(stdout);
        co_yield();
    }
}

void test1() {

    co_sched_t sched = co_sched_create();

    co_sched_create_task(sched, 0U, test1_fun1, "task0");
    co_sched_create_task(sched, 0U, test1_fun1, "task1");
    co_sched_create_task(sched, 0U, test1_fun1, "task2");
    co_sched_create_task(sched, 0U, test1_fun1, "task3");
    co_sched_create_task(sched, 0U, test1_fun1, "task4");
    co_sched_create_task(sched, 0U, test1_fun1, "task5");
    co_sched_create_task(sched, 0U, test1_fun1, "task6");
    co_sched_create_task(sched, 0U, test1_fun1, "task7");
    co_sched_create_task(sched, 0U, test1_fun1, "task8");
    co_sched_create_task(sched, 0U, test1_fun1, "task9");
    co_sched_create_task(sched, 0U, test1_fun1, "task10");
    co_sched_create_task(sched, 0U, test1_fun1, "task11");
    co_sched_create_task(sched, 0U, test1_fun1, "task12");

    co_sched_runloop(sched);
    co_sched_destroy(sched);
}

#include <arpa/inet.h>  // inet_addr
#include <netinet/in.h> // sockaddr_in
#include <sys/socket.h>

void test2_fun1(void *arg) {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        printf("socket create error!\n");
        fflush(stdout);
        printf("error: (%d) %s\n", errno, strerror(errno));
        return;
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int retval = connect(fd, (struct sockaddr *) &addr, sizeof(addr));
    printf("retval=%d\n", retval);
    if (retval != 0) {
        fflush(stdout);
        printf("error: (%d) %s\n", errno, strerror(errno));
    }
    fflush(stdout);
}

void test2() {
    co_hooks_enable(1);
    co_sched_t sched = co_sched_create();

    co_sched_create_task(sched, 0U, test2_fun1, NULL);

    co_sched_runloop(sched);
    co_sched_destroy(sched);
}

#include <co_epoll.h>
#include <fcntl.h>

void test3() {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        printf("socket() error: (%d) %s\n", errno, strerror(errno));
        fflush(stdout);
        return;
    }
    int retval;
    int flags = fcntl(fd, F_GETFL, 0);
    if (!(flags & O_NONBLOCK))
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(2593);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    retval = connect(fd, (struct sockaddr *) &addr, sizeof(addr));
    printf("retval=%d\n", retval);
    if (retval != 0) {
        if (errno == EINPROGRESS) {
            printf("Operation now in progress\n");
            fflush(stdout);
        } else {
            printf("error: (%d) %s\n", errno, strerror(errno));
            fflush(stdout);
            return;
        }
    }
    int epfd = co_epoll_create(1);
    struct co_epoll_events ev;
    ev.events = CO_EPOLLIN | CO_EPOLLOUT | CO_EPOLLERR | CO_EPOLLHUP;
    retval = co_epoll_ctl(epfd, CO_EPOLL_CTL_ADD, fd, &ev);
    if (retval != 0) {
        printf("co_epoll_ctl() error: (%d) %s\n", errno, strerror(errno));
        fflush(stdout);
        return;
    }
    const int ev_rsts_max = 100;
    struct co_epoll_events *ev_rsts = calloc(ev_rsts_max, sizeof(struct co_epoll_events));
    retval = co_epoll_wait(epfd, ev_rsts, ev_rsts_max, 1000);
    printf("retval=%d\n", retval);
    fflush(stdout);

    free(ev_rsts);
    co_epoll_destroy(epfd);
}

int main(int argc, char *argv[]) {
    // dbg_log_level(DLI_WARN);
    LENTRY("(argc:%d, argv:%p)", argc, argv);
    // main1(argc, argv);
    test1();
    dbg_leaks_report(stdout);
    LEXIT("(%d)", 0);
    return 0;
}
